home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / prolog / ai.prl / mike1.exe / ENGINE2.PL < prev    next >
Encoding:
Text File  |  1990-09-17  |  22.1 KB  |  598 lines

  1. /* file: ENGINE2.PL {2nd part of main code for MIKE rule/frame engine} */
  2. /*       see also ENGINE1.PL for earlier bits!                         */
  3. /*                          *************
  4.                                M I K E
  5.                             *************
  6.                Micro Interpreter for Knowledge Engineering
  7.                   {written in Edinburgh-syntax Prolog}
  8.  
  9. Copyright (C) 1989, 1990  The Open University (U.K.)
  10.  
  11. This software accompanies Open University Study Pack PD624, 'KNOWLEDGE
  12. ENGINEERING'.  Complete sets of study pack materials may be obtained from:
  13.  
  14.                       Learning Materials Sales Office
  15.                       The Open University
  16.                       P.O. Box 188
  17.                       Milton Keynes MK7 6DH, U.K.
  18.  
  19.                       Tel: [+44] (908) 653338
  20.                       Fax: [+44] (908) 653744
  21. */
  22. /* ENGINE1.PL & ENGINE2.PL contain the essential innards of MIKE.
  23.    Some auxilliary code is contained in the files UTIL.PL and IO.PL,
  24.    and the kernel of the forward chaining executive loop is in FC_EXEC.PL
  25.    ENGINE1.PL & ENGINE2.PL are subdivided into six main parts, as follows:
  26.    (N.B. the first three parts are in file ENGINE1.PL)
  27.    1.  Backward chaining
  28.    2.  Frame manipulation
  29.    3.  Demon processing
  30.    (N.B. the last three parts are in file ENGINE2.PL)
  31.    4.  Top level
  32.    5.  Forward chaining (left hand side conditions)
  33.    6.  Forward chaining (right hand side actions)
  34. */
  35.  
  36. /* ===================== (4) T O P   L E V E L ========================== */
  37. A & B :-
  38.     and(A & B).
  39.  
  40. (X instance_of Y):-
  41.    (X instance_of Y with _).
  42. (X subclass_of Y):-
  43.    (X subclass_of Y with _).
  44.  
  45. and(initialise):- initialise.
  46. and(go):- !, go.
  47. and(X & Y) :- and(X),and(Y).
  48. and(X):- perform1(X,New,'top level','You told me so'),
  49.     retract('pd624 wme'(Whatever)),
  50.     assert('pd624 wme'([New|Whatever])).
  51.     
  52. fc:-
  53.   initialise,
  54.   add start,
  55.   go.
  56.  
  57. /* It would be faster to use 'continue' instead of 'go' in the line above,
  58. because 'go' now invokes part_initialise, which is actually redundant in
  59. this precise context.  However, the above definition is published in the
  60. course text, so we stick with it.
  61. */
  62.  
  63. fc(X):-
  64.   initialise,
  65.   add X,
  66.   go.
  67. /* See preceding comment about using 'continue' instead of 'go' */
  68.  
  69. add X :- /* fc triggers off the forward chainer */
  70.     assert(currentdb(X,true)),
  71.     assert(justification(X,'top level','You told me so')),
  72.     (retract('pd624 wme'(Whatever));Whatever = []),
  73.     assert('pd624 wme'([X|Whatever])),!.
  74.     
  75. remove X :-
  76.    retract(currentdb(X,Truth)),!.
  77. remove X :-
  78.    'pd624 write'(['Sorry : ',X,' is not in working memory',nl,
  79.    'and thus cannot be removed',nl]).
  80.  
  81. note ((A with B)) :-
  82.   nonvar(B),
  83.   retract((A with C)), /* previous definition? then warn user... */
  84.   'pd624 write'(['Warning: overwriting previous definition of ',A,nl,
  85.   ' with ',B,'. ',nl,'New definition is: ',A,nl,'with ',B,'. ',nl]),
  86.   assert((A with B)),!.
  87. note ((A with B)) :-
  88.   nonvar(B),
  89.   assert((A with B)).  /* come here if no previous definition */
  90. note ((A with B)) :-
  91.   var(B),              /* anomalous case... inform user */
  92.   'pd624 write'(['Error: ',B,' is a variable but must instead be ',nl,
  93.   'a legal frame body.  No changes have resulted, and instruction',nl,
  94.   'will be ignored',nl]),!. /* ! protects 'pd624 write' */
  95.  
  96. note X:-
  97.     perform1(note X,New,'top level','You told me so'),
  98.     (retract('pd624 wme'(Whatever));Whatever = []),
  99.     assert('pd624 wme'([New|Whatever])),!.
  100.  
  101. deduce X :-
  102.   prove(X).    
  103.  
  104. initialise:-
  105.  fc_reset_history,      /* reset history counters (see fc_exec.pl) */
  106.     abolish(currentdb,2),   /* the relation 'currentdb/2' stores all WM items */
  107.     kill(currentdb),  /* just for portability */
  108.     abolish(already_did,2), /* used for quick refractoriness test */
  109.     kill(already_did),
  110.     assert(already_did(nil,nil)), /* need some assertion to avoid run-time complaint */
  111. abolish('pd624 wme',1),    /* otherwise we end up in a curious state?!!! */
  112.     kill('pd624 wme'),
  113.     abolish(receives_answer,2),
  114.     abolish(justification,3),
  115.     assert('pd624 wme'([])),
  116.  (retract(pd624_flag(_)) ; true), /* Used for single-step trace. See UTIL.PL */
  117.  initialise_back_door,  /* in case of later extensions ! */
  118.  !.
  119.  
  120. /*
  121.    part_initialise is like initialise, but leaves WM alone, and
  122.    also leaves justifications arising from top level use of ?- add ...
  123. */
  124. part_initialise :-
  125.  fc_reset_history,      /* reset history counters (see fc_exec.pl) */
  126.     abolish(already_did,2), /* used for quick refractoriness test */
  127.     kill(already_did),
  128.     assert(already_did(nil,nil)), /* need some assertion to avoid run-time complaint */
  129. abolish('pd624 wme',1),    /* otherwise we end up in a curious state?!!! */
  130.     kill('pd624 wme'),
  131.     abolish(receives_answer,2),
  132.  retractall(justification(Pat,'top level','You told me so')),
  133.     assert('pd624 wme'([])),
  134.  (retract(pd624_flag(_)) ; true), /* Used for single-step trace. See UTIL.PL */
  135.  initialise_back_door,  /* in case of later extensions ! */
  136.  !.
  137.  
  138.  
  139. initialise_back_door :-
  140.   allowable_back_door_initialise(X),   /* back door utility defined? */
  141.   do_just_once(call(X)),               /* then invoke it once */
  142.   fail.                                /* backtrack for others */
  143.  
  144. initialise_back_door.                  /* default success */
  145.  
  146. allow_back_door_initialise(Pred) :-           /* to be used as a directive */
  147.    allowable_back_door_initialise(Pred);      /* already there? do nothing */
  148.    assertz(allowable_back_door_initialise(Pred)). /* else add flag */
  149.  
  150.  
  151. announce P :-
  152.          'pd624 write'(P),!.    /* simple output of list of items */
  153.  
  154. /* PATCH 19-SEP-90: We now distinguish between 'continue' and 'go'.
  155.    The former really leaves ALL internal state information alone
  156.    (e.g. what rules have recently fired), and carries on forward
  157.    chaining, if possible.  The latter ('go') leaves working memory
  158.    alone, as promised, but clears up various internal flags, so
  159.    that a brand new run of forward chaining can be invoked with the
  160.    current working memory (this is what most users expect anyway) */
  161.  
  162. continue :- 'pd624 wme'(A),!,forward_chain.
  163. continue :- assert('pd624 wme'([])),forward_chain.
  164.  
  165. go :-
  166.   part_initialise, /* get rid of hidden flags like 'already_did'...*/
  167.   forward_chain.
  168.  
  169. the X of Y is Z:-
  170.     prove(the X of Y is Z).
  171. the X of Y > Z:-
  172.     prove(the X of Y > Z).
  173. the X of Y < Z:-
  174.     prove(the X of Y < Z).
  175.  
  176. all X of Y are Z:-
  177.     prove(all X of Y are Z).
  178.  
  179. wm:-
  180.     'pd624 write'(['The current contents of working memory are',
  181.     nl,'the following : ',nl]),
  182.     assert('wm counter'(0)),
  183.     currentdb(X,Y),
  184.     do_just_once((tab(5),write_db(X,Y),nl,
  185.                   retract('wm counter'(P)),
  186.                   New is P + 1,
  187.                   assert('wm counter'(New)) )),
  188.     fail.
  189. wm:-
  190.     retract('wm counter'(Number)),
  191.     'pd624 write'([nl,'A total of ',Number,
  192.      ' current working memory elements were found.',nl]).
  193.  
  194. write_db(X,false):-
  195.     write(X),write(' is known to be false'),!.
  196. write_db(X,_):-
  197.     write(X).
  198.  
  199. /* this defines the de facto conflict resolution strategy, namely
  200.    refractoriness
  201.    recency
  202.    specificity
  203.        - - - applied in that order */
  204. current_conflict_resolution_strategy([refractoriness,recency,specificity]).
  205.  
  206. /* ==================== (5) F O R W A R D  C H A I N I N G =========== */
  207. /* ====================    Left-hand-side conditions       =========== */
  208.  
  209. /* N.B. The forward chaining executive loop is stored separately in the file
  210. FC_EXEC.PL. It has been separated in order to keep this file (ENGINE.PL) a
  211. manageable size.   */
  212.  
  213. /* ----- all_in_wm (sees whether all of its args are present in WM) ---- */
  214. all_in_wm(A or B):-
  215.     all_in_wm(A), !.
  216. all_in_wm(_ or B):-
  217.     all_in_wm(B), !.
  218. all_in_wm(Pattern1 & Rest) :-
  219.     !,
  220.  when_enabled('show individual LHS in' for Pattern1),
  221.     in_wm(Pattern1),
  222.  when_enabled('show individual LHS out' for Pattern1),
  223.     all_in_wm(Rest).
  224.  
  225. all_in_wm(Pattern) :- /*singleton*/
  226.  when_enabled('show individual LHS in' for Pattern),
  227.     in_wm(Pattern),
  228.  when_enabled('show individual LHS out' for Pattern).
  229.  
  230. /* ------------------------ Conflict resolution ------------------------- */
  231.  
  232. resolve_conflicts(List,Item,_,[]):-  /* when you've exhausted conflict resolution */
  233.     first_filter(List,Item),!.               /* choose the first */
  234.     /* first filter just takes the first item in the list.  This can
  235.     be achieved more efficiently, but is not for the sake of tracing.
  236.     If tracing is deemed not to be important make the clause head of the
  237.     first clause resolve_conflicts([H|_],Item,_,[]) instead.  A second clause
  238.     resolve_conflicts([],_,_,[]) will also be necessary to cater for an
  239.     empty conflict set */
  240. resolve_conflicts(Set,H,WME,[Strategy|Rest]):-
  241.     DO_It =.. [Strategy,Set,WME,Newset],
  242.     DO_It,
  243.     resolve_conflicts(Newset,H,WME,Rest).
  244.  
  245. first_filter([],(rule 'didnt find a winner' forward if 'no ifs' then
  246.                      'no thens')):- !.
  247. first_filter([H|_],H).     /* choose the first item */
  248.  
  249. /* conflict resolution strategies ---- user-modifiable */
  250.  
  251. /* if you design your own conflict resolution rules they must be of the form
  252. <name>(Input_set,Working_memory_elements,Output_set).
  253.  
  254. The types of conflict resolution are
  255. refractoriness: a particular rule with a given set of instantiations
  256.   is precluded from firing again
  257. recency: a weighting is done and only those rules whose pre conditions
  258.   corespond most closely to the latest items in working memory are chosen
  259. specificity: the rules whose preconditions are most clearly specified
  260.   (i.e. most left-hand-side conditions) are fired next
  261. */
  262.  
  263. refractoriness([],_,[]).
  264. refractoriness([(rule Rule forward if COND then Actions)|Rest],_,Output):-
  265.     already_did(Rule,COND),!,
  266.     when_enabled('show refractoriness' for Rule),
  267.     refractoriness(Rest,_,Output).
  268. refractoriness([H|Rest],_,[H|Output]):-
  269.     refractoriness(Rest,_,Output).
  270.  
  271. recency([],_,[]).
  272. recency(Set,Wme,NewSet):-
  273.     rank_candidates(Set,Wme,RankedSet),
  274.     choose_most_likely_set(RankedSet,0,[],NewSet),
  275.     when_enabled('show recency' for NewSet).
  276.  
  277. rank_candidates([],_,[]).
  278. rank_candidates([(rule Rule forward if Cond then Actions)|Rest],Wme,
  279.                 [(Rank,(rule Rule forward if Cond then Actions))|NewRest]):-
  280.     make_rank(Cond,Wme,0,Rank),
  281.     rank_candidates(Rest,Wme,NewRest).
  282.  
  283. make_rank(H or T,Wme,A,Rank):-
  284.     make_rank(H,Wme,A,T1),
  285.     make_rank(T,Wme,A,T2),
  286.     Rank is T1 + T2.
  287. make_rank(H &T,Wme,A,B):-
  288.     'pd624 member'(H,Wme),
  289.     A1 is A + 1,
  290.     make_rank(T,Wme,A1,B).
  291. make_rank(_ & T,Wme,A,B):-
  292.     make_rank(T,Wme,A,B).
  293. make_rank(A,Wme,B,C):-
  294.     'pd624 member'(A,Wme),
  295.     C is B + 1 .
  296. make_rank(L,_,A,A).
  297.  
  298. choose_most_likely_set([],_,A,A).
  299. choose_most_likely_set([(A,H)|Tail],Crit,Result,Set):-
  300.     Crit > A,
  301.     choose_most_likely_set(Tail,Crit,Result,Set).
  302. choose_most_likely_set([(A,H)|Tail],Crit,Result,Set):-
  303.     Crit = A,
  304.     choose_most_likely_set(Tail,Crit,[H|Result],Set).
  305. choose_most_likely_set([(A,H)|Tail],Crit,Result,Set):-
  306.     A > Crit,
  307.     choose_most_likely_set(Tail,A,[H],Set).
  308.  
  309. specificity([],_,[]).   /* when there are no applicable rules */
  310. specificity(Set,Wme,Output):-
  311.     specificity1(Set,Wme,Ranked_set),
  312.     choose_most_likely_set(Ranked_set,0,[],Output),
  313.     when_enabled('show specificity' for Output).
  314.  
  315. specificity1([],_,[]).
  316. specificity1([(rule Rule forward if Cond then Actions)|Rest],_,[(Length,(rule Rule forward if Cond then Actions))|Set]):-
  317.      'pd624 length with disjunct check'(Cond,Length),  /* see UTIL.PL */
  318.      specificity1(Rest,_,Set).
  319.  
  320. /* if a rule has a disjunction on the LHS and both elements of that disjunction
  321. are true then it will appear multiple times in the conflict set e.g.
  322.   rule eg forward if a(P) or b(P) then c(P) given
  323.   a(1) and b(2)
  324.   will result in both instantiations (i.e. c(1) and c(2)) appearing in the
  325.   conflict set.  HOWEVER if the rule is instead 'a or b then c', this will
  326.   lead to the same rule in the conflict set twice, but via different routes.
  327.   c'est la guerre */
  328.  
  329. /* ----------------------------- in_wm -------------------------------- */
  330. in_wm(A or B):-
  331.   in_wm(A).
  332. in_wm(A or B):-
  333.   in_wm(B).
  334.  
  335. in_wm(-- X) :-
  336.     !,
  337.     not(in_wm(X)).
  338.  
  339. in_wm(deduce X) :-
  340.     !,
  341.     do_just_once(prove(X)). /* runs backward rules for that pattern! */
  342. /* N.B. change above line to simply
  343.    prove(X)
  344. if you disagree with the large comment below, i.e. if you want
  345. there to be multiple solutions whenever 'deduce' is used on the
  346. left hand side of a rule */
  347. /* Notice that arbitrary backtracking is NOT allowed in consecutive
  348.    calls to deduce which occur on the left hand side of a
  349.    forward-chaining rule!!!!! -- the call to
  350.    do_just_once above prevents this.  Arbitrary backtracking is allowed
  351.    within sequences of backward-chaining rules, however.
  352.    In other words, suppose we had two rules such as the following:
  353.  
  354.    rule init forward
  355.      if
  356.        start
  357.      then
  358.        remove start &
  359.        add [fred, is, happy] &
  360.        add [mary, is, happy] &
  361.        add [mary, likes, potatoes].
  362.  
  363.    rule temp forward
  364.      if
  365.        -- start &
  366.        deduce [X, is, happy] &
  367.        deduce [X, likes, potatoes]
  368.      then
  369.        add [X, isa, happy_potato_eater].
  370.  
  371. Rule temp will never find a happy_potato_eater, because the first call
  372. to deduce will succeed with X = fred, but deduce [fred, likes, potatoes]
  373. will fail, and the first call will not be redone!!  However, either of
  374. the next two temp rules would do the trick (along with the backward
  375. chaining rule 'potato_eater':
  376.  
  377.     rule temp2 forward
  378.       if
  379.         -- start &
  380.         [X, is, happy] &
  381.         [X, likes, potatoes]
  382.       then
  383.         add [X, isa, happy_potato_eater].
  384.  
  385.     rule temp3 forward
  386.       if
  387.         -- start &
  388.         deduce [X, isa, happy_potato_eater]
  389.       then
  390.         announce ['Hooray, I have discoverd a happy potato eater: ', X].
  391.  
  392.     rule potato_eater backward
  393.       if                     (because this is backward chaining..)
  394.         [X, is, happy] &     (arbitrary calls to deduce would be OK, also)
  395.         [X, likes, potatoes] (arbitrary calls to deduce OK, also)
  396.       then
  397.         [X, isa, happy_pototo_eater].
  398. */
  399.  
  400. /* execute prolog goal */
  401. in_wm(prolog(X)):-
  402.     !,
  403.     X.
  404.  
  405. /* If we look for, say, (the father of enrico is X), then we will not really
  406. find it in working memory, but instead invoke fetch/5 to do the
  407. real work inside the frame representation, just as we do in the
  408. case of backward chaining.  Notice that fetch/5 on its own does
  409. pure frame accessing (possibly looking up the class hierarchy),
  410. but does NOT itself invoke the backward chainer */
  411.  
  412. in_wm(the Slot of Object is Filler) :- /* the basic frame form */
  413.     fetch(Object, Slot, Filler, [Object], _).
  414. in_wm(A receives_answer B):-
  415.     A receives_answer B.    
  416. in_wm(all X of Y are What) :-
  417.     findall(Out,fetch(Y,X,Out,[Y],_),What). /* What is order sensitive,BEWARE! */    
  418. in_wm(the A of B > C):-
  419.           do_just_once(prove(the A of B > C)). /* no backtracking!! */
  420. in_wm(the A of B < C):-
  421.           do_just_once(prove(the A of B < C)).
  422.  
  423. /* N.B. change above line to simply
  424.    prove(the A of B < C)
  425. (and similarly for 3 lines above!!!)
  426. if you disagree with the huge comment about a page earlier, i.e. if you want
  427. there to be multiple solutions whenever 'deduce' is used on the
  428. left hand side of a rule */
  429.  
  430. in_wm(A instance_of B):-
  431.   A instance_of B with _whatever.
  432. in_wm(A subclass_of B):-
  433.   A subclass_of B with _some_body.
  434.  
  435. in_wm(Pattern) :-
  436.  currentdb(Pattern,true).  /* this is the basic WM assertion form */
  437.  
  438. /* Back door case, for extensions to MIKE */
  439. in_wm(X):-allowable_prolog_lhs(X), !, call(X).
  440.  
  441. /* 'Back door' enables us to extend the syntax of MIKE with calls to
  442.     arbitrary lumps of Prolog:
  443.     Note that the following two predicates are intended to be used as
  444.     DIRECTIVES (analogous to ?-op(A,B,C)).  The 'allow...' directive
  445.     makes an assertion of the form 'allowable...' for testing by MIKE.
  446. */
  447. /* If database assertion is present then ignore, else make assertion */
  448. allow_prolog_lhs(Pattern) :-
  449.    allowable_prolog_lhs(Pattern); assertz(allowable_prolog_lhs(Pattern)).
  450.  
  451. allow_prolog_rhs(Pattern) :-
  452.    allowable_prolog_rhs(Pattern);assertz(allowable_prolog_rhs(Pattern)).
  453.  
  454.  
  455.  
  456. /* ================= (6) F O R W A R D  C H A I N I N G =============== */    
  457. /* =================       Right-hand-side actions      =============== */
  458. perform(Action1 & Rest,List,Rule,Conds) :-
  459.     !,
  460.     do_just_once(perform1(Action1,A,Rule,Conds)), /* PATCH 11/1/90 */
  461.     perform(Rest,R,Rule,Conds),
  462.     append(A,R,List).
  463.  
  464. perform(Action,A,Rule,Conds) :-  /* singleton case */
  465.     perform1(Action,A,Rule,Conds).
  466.  
  467. perform1(prolog(Action),[],Rule,Conds) :-
  468.     !,
  469.     call(Action).
  470. perform1(remove Pattern,[],Rule,Conds) :-
  471.     !,
  472.     retract(currentdb(Pattern,true)).
  473. perform1(strategy List,[],Rule,Conds):-
  474.     strategy List.
  475.  
  476. /* Note the second argument to perform1 in the next three cases, which is
  477.       the output of the new working memory elements.
  478.    This is redundant storage because the user could have later referenced the
  479.    answer to this question in one of two ways, either in the standard facet
  480.    form, i.e. the A of B is C, or they could have checked the question
  481.    answer specifically, in the form the A of B receives_answer C.  Since all
  482.    New Working Memory is used for is summation, redundancy will not effect
  483.    the final outcome.  For this reason, both forms can be added back to
  484.    the conflict resolution component with safety. */
  485. perform1((query the A of B receives_answer C),
  486.          [the A of B receives_answer C,the A of B is C],Rule,Conds):-
  487.  answer_vetting(C),
  488.     (query the A of B receives_answer C),
  489.     assert(justification((the A of B is C),Rule,'You told me so')).
  490. perform1((query the A of B is C receives_answer yes),
  491.          [the A of B is C receives_answer yes, the A of B is C],Rule,Conds):-
  492.  answer_vetting(C),
  493.     (query the A of B is C receives_answer yes),
  494.     assert(justification((the A of B is C),Rule,'You told me so')).
  495. perform1((query Quest receives_answer Ans),
  496.          [Quest receives_answer Ans],Rule,Conds):-
  497.  answer_vetting(C),
  498.     (query Quest receives_answer Ans),
  499.     assert(justification(Quest,Rule,'You told me so')).
  500. perform1(note (A instance_of B with C),[],Rules,Conds):-
  501.   retract((A instance_of B with Body)),
  502.   'pd624 write'(['Warning : overwriting previous definition of ',A,
  503.     nl,' instance of ',B,' with body ',Body,nl,' with the new body ',
  504.     C,'. ',nl]),
  505.   assert((A instance_of B with C)),
  506.   assert(justification((A instance_of B with C),Rules,Conds)),!.
  507. perform1(note (A instance_of B with C),[A instance_of B],Rule,Conds):-
  508.  assert((A instance_of B with C)),
  509.  assert(justification((A instance_of B with C),Rule,Conds)),
  510.  !. /* cut needed to stop overinstantiation
  511.  in the following clauses in cases of failure */
  512. perform1(note (A subclass_of B with C),[],Rules,Conds):-
  513.   retract((A subclass_of B with Body)),
  514.   'pd624 write'(['Warning : overwriting previous definition of ',A,
  515.     nl,' subclass of ',B,' with body ',Body,nl,' with the new body ',
  516.     C,'. ',nl]),
  517.   assert((A subclass_of B with C)),
  518.   assert(justification((A subclass_of B with C),Rules,Conds)).
  519. perform1(note (A subclass_of B with C),[A subclass_of B],Rule,Conds):-
  520.  assert((A subclass_of B with C)), !. /* cut needed to stop overinstantiation
  521.  in the following clauses in cases of failure */
  522.  
  523. perform1(note the A of O is V,[the A of O is V],Rule,Conds):-
  524.     store(O,A,V),
  525.     assert(justification((the A of O is V),Rule,Conds)).
  526.  
  527. perform1( (note X), _,Context,_) :-  /* PATCH NEW ERROR MSG 20-SEP-90 */
  528.   not( X = ( the _ of _ is _ ) ),         /* IF PATTERN IS NOT THIS ONE */
  529.   not( X = ( _ subclass_of _ with _ ) ),  /* NOR THIS ONE... */
  530.   not( X = ( _ instance_of _ with _ ) ),  /* NOR THIS ONE... */
  531.   nl,                                     /* THEN IT IS A MISTAKE! */
  532.   write('ERROR... you have attempted the following'),
  533.   'pd624 tell me context'(Context),write(':'),nl,
  534.   write('     note '),write(X),nl,
  535.   write('HOWEVER, note can only be used with one of these 3 formats:'),nl,
  536.   write('  a) note the X of Y is Z.'),nl,
  537.   write(
  538. '  b) note (Obj1 instance_of Obj2 with Slot1:Filler1, Slot2:Filler2, ...).'),
  539.   nl,
  540.   write(
  541. '  c) note (Obj1 subclass_of Obj2 with Slot1:Filler1, Slot2:Filler2, ...).'),
  542.   nl,
  543.   write('(Most frames can be developed/saved in a file using a text editor.)'),
  544.   nl,
  545.   !,
  546.   fail.
  547.  
  548. perform1(add the A of O is V,[],Rule,Conds):- /* PATCH NEW ERROR MSG 11/1/90 */
  549.   write('ERROR: add can only be used for working memory patterns (use note)'),
  550.   nl.
  551. perform1(add Pattern, [Pattern],Rule,Conds) :- /* identical to next case with keyword */
  552.     update_wm(Pattern),
  553.     assert(justification(Pattern,Rule,Conds)).
  554. perform1(announce Pattern,[],Rule,Conds):-
  555.  'pd624 write'(Pattern),nl.
  556. perform1(the X of Y is Z,[],R,C) :- /* PATCH 14/6/90 */
  557.   'pd624 write'(['ERROR: the ',X,' of ',Y,' is ',Z,nl,
  558.   'appeared on the right hand side of a rule.  Use note if you want to',nl,
  559.   'change a frame, or prolog(the ',X,' of ',Y,' is <VAR>)',nl,
  560.   'to retrieve a slot filler in this context.',nl]), !.
  561.  
  562. /* 'Back door' case... see code for allow_prolog_rhs above */
  563. perform1(Action,[],Rule,Conds) :-
  564.  allowable_prolog_rhs(Action),
  565.  !,
  566.  call(Action).
  567.  
  568. perform1(Pattern,[Pattern],Rule,C) :-    update_wm(Pattern),
  569. /* default case is to add Pattern to WM */
  570. assert(justification(Pattern,Rule,C)).  /* PATCH ADDED 11/1/90 */
  571. perform1(P,[],Rule,C):-    writel(['ERROR: the following Right-hand
  572. side of a rule failed',P]).
  573.  
  574. update_wm(the Attribute of Object is Value) :- /* frame syntax? */
  575.     store(Object, Attribute, Value). /* utility to update frame representation */
  576. update_wm(all Attributes of Object are [Value1 | Values]) :-
  577.     store(Object, Attributes, [Value1|Values]). /* must unify with list! */
  578.  
  579. update_wm(OTHER) :-
  580.     retract(currentdb(OTHER,TRUTH)),     /* already there? then overwrite it */
  581.     !,
  582.     assert(currentdb(OTHER,true)).
  583. update_wm(OTHER) :- /* must not have been there before, so add afresh */
  584.     assert(currentdb(OTHER,true)).
  585.  
  586.  
  587. 'pd624 tell me context'('top level') :-
  588.    !.
  589.  
  590. 'pd624 tell me context'(Name) :-
  591.    ((rule Name forward if _ then _) ;
  592.     (rule Name backward if _ then _)),
  593.    write(' within rule '),write(Name),
  594.    !.
  595.  
  596. 'pd624 tell me context'(Name) :-
  597.    write(' from '),write(Name).
  598.